Imports Microsoft.VisualBasic
Imports System.Collections.Specialized
Imports System.Web
Imports System.Xml

Imports System.Xml.XPath



Public NotInheritable Class EntrezController
    Implements IDisposable


    Private service As New eUtils.eUtilsService

    Public Sub New()
        service.Timeout  = -1

    End Sub

    Public Function GetDatabases() As IDictionary


        Dim result As eUtils.eInfoResultType

        result = Me.service.run_eInfo_MS(String.Empty, My.Settings.Tool, My.Settings.EmailAddress)

        Dim dbs As New Specialized.OrderedDictionary()


        If result IsNot Nothing AndAlso String.IsNullOrEmpty(result.ERROR) Then

            For Each db As String In result.DbList.Items

                dbs.Add(db, String.Empty)

            Next


        Else

            dbs.Add("error", result.ERROR)

        End If

        Return dbs

    End Function

    Public Function GetSupportedDatabases() As IDictionary


        Dim dbs As New Specialized.OrderedDictionary

        Dim databaseNode As XPathNodeIterator

        Try
            Dim listDoc As XPathDocument
            Dim listNavigator As XPathNavigator

            listDoc = New XPathDocument(HttpContext.Current.Server.MapPath(My.Settings.DatabaseConfigFile))


            listNavigator = listDoc.CreateNavigator

            Dim dbXPath As String

            dbXPath = String.Format(My.Settings.SupportedDatabasesXPath)


            databaseNode = listNavigator.Select(dbXPath)

            Do While databaseNode.MoveNext

                dbs.Add(databaseNode.Current.GetAttribute("Name", String.Empty), _
                    databaseNode.Current.GetAttribute("FriendlyName", String.Empty))

            Loop

        Catch ex As Exception

            dbs.Add("error", ex.Message)


        End Try

        Return dbs


    End Function

    Public Function GetDocumentSummariesByUids(ByVal dbName As String, ByVal uids() As Integer, _
        ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader

        Dim links As New Dictionary(Of Integer, String)

        For Each uid As Integer In uids

            'links.Add(New EntrezLink(uid, dbName))
            links.Add(uid, dbName)

        Next

        Return GetDocumentSummariesByUids(links, pageIndex, pageSize)

    End Function

    Public Function GetDocumentSummariesByUids _
        (ByVal uids As Dictionary(Of Integer, String), ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader


        Dim summaries As New SummaryDataReader

        For Each item As KeyValuePair(Of Integer, String) In uids
            'do while uids.GetEnumerator.MoveNext



            ' retreives document Summaries by list of primary IDs
            Try
                Dim res As eUtils.eSummaryResultType

                'Using serv As New eUtils.eUtilsService


                ' call NCBI ESummary utility
                res = Me.service.run_eSummary_MS(item.Value, item.Key.ToString, _
                    String.Empty, String.Empty, pageIndex.ToString, pageSize.ToString, _
                    My.Settings.Tool, My.Settings.EmailAddress)

                'res = serv.run_eSummary_MS(uids.GetEnumerator.Current.Value, uids.GetEnumerator.Current.Key.ToString, _
                '    String.Empty, String.Empty, pageIndex.ToString, pageSize.ToString, _
                '    My.Settings.Tool, My.Settings.EmailAddress)

                'End Using


                ' results output
                summaries.Import(New SummaryDataReader(item.Value, res.DocSum))

            Catch


            End Try

            'Loop

        Next

        Return summaries

    End Function

    Public Function GetDocumentSummaryByUid _
    (ByVal dbName As String, ByVal uid As Integer, ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader


        Dim summaries As New SummaryDataReader

        ' retreives document Summaries by list of primary IDs
        Try
            Dim res As eUtils.eSummaryResultType

            'Using serv As New eUtils.eUtilsService


            ' call NCBI ESummary utility
            res = Me.service.run_eSummary_MS(dbName, uid.ToString, _
                String.Empty, String.Empty, pageIndex.ToString, pageSize.ToString, _
                My.Settings.Tool, My.Settings.EmailAddress)

            'End Using


            ' results output
            summaries = New SummaryDataReader(dbName, res.DocSum)

        Catch


        End Try



        Return summaries

    End Function

#Region "Search Functions"
    Public Function SearchByAuthor(ByVal dbName As String, ByVal author As String, _
        ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader

        Return Me.Search(dbName, author, "Author", pageIndex, pageSize)

    End Function

    Public Function SearchAllFields(ByVal dbName As String, ByVal searchString As String, _
        ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader

        Return Me.Search(dbName, searchString, String.Empty, pageIndex, pageSize)


    End Function

    Public Function Search(ByVal dbName As String, ByVal searchString As String, ByVal fieldName As String, _
        ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader


        If String.IsNullOrEmpty(searchString) Then

            Return New SummaryDataReader(New List(Of SummaryDataRecord))

        End If

        Return Me.GetSummaries(dbName, searchString, fieldName, pageIndex, pageSize)

    End Function

#End Region

#Region "Private Methods"

#Region "Shared Methods"


    Private Shared Function ParseUids(ByVal res As eUtils.eSearchResultType) As Integer()

        Dim list As New List(Of Integer)


        For Each id As String In res.IdList
            list.Add(Convert.ToInt32(id))

        Next

        Return list.ToArray

    End Function

    Private Shared Function AddLinksToDictionary(ByVal dict As Dictionary(Of Integer, String), ByVal ids() As Integer, ByVal dbName As String) As Dictionary(Of Integer, String)

        For Each id As Integer In ids
            dict.Add(id, dbName)
        Next


        Return dict

    End Function
#End Region

    Private Function GetSummaries(ByVal dbName As String, ByVal searchString As String, _
        ByVal fieldName As String, ByVal pageIndex As Integer, ByVal pageSize As Integer) As SummaryDataReader


        Try

            'Dim uids As EntrezLinkList = New EntrezLinkList()
            Dim uids As New Dictionary(Of Integer, String)

            'Using serv As New eUtils.eUtilsService

            Dim formatter As ISearchFieldFormatter


            If String.IsNullOrEmpty(dbName) OrElse dbName.ToLower = "entrez" Then
                ' call NCBI EGQuery utility   
                ' run_eGquery_MS provides Entrez database counts for a single search

                Dim res As eUtils.GQueryResultType

                formatter = Database.GetDatabase("entrez").CreateSearchFieldFormatter(fieldName)

                res = Me.service.run_eGquery_MS(formatter.ToSearchString(searchString), _
                    My.Settings.Tool, My.Settings.EmailAddress)

                Dim dbsToSearch As New StringCollection

                For Each item As eUtils.ResultItemType In res.eGQueryResult.ResultItem

                    If Convert.ToDouble(item.Count) > 0 Then dbsToSearch.Add(item.DbName)

                Next

                uids = Me.GetListOfUids(searchString, dbsToSearch, pageIndex, pageSize)

            Else
                ' call NCBI eSearch utility   
                ' run_eSearch_MS provides uids of articles for a given database

                Dim res As eUtils.eSearchResultType

                formatter = Database.GetDatabase(dbName).CreateSearchFieldFormatter(fieldName)

                res = Me.service.run_eSearch_MS(dbName, formatter.ToSearchString(searchString), _
                   String.Empty, String.Empty, String.Empty, My.Settings.Tool, My.Settings.EmailAddress, _
                   String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, _
                   pageIndex.ToString, pageSize.ToString, String.Empty, String.Empty)



                'uids.AddRange(Me.ParseUids(res), dbName)
                uids = AddLinksToDictionary(uids, ParseUids(res), dbName)



            End If


            Return Me.GetDocumentSummariesByUids(uids, pageIndex, pageSize)


            'End Using

        Catch ex As Exception

            Debug.WriteLine("Error GetSummaries: ")
            Debug.WriteLine(ex.StackTrace)
            Debug.WriteLine("End Error")

            Throw ex

            'Return New SummaryDataReader(dbName, New List(Of eUtils.DocSumType))

        End Try

    End Function

    Private Function GetListOfUids(ByVal searchString As String, _
            ByVal dbs As StringCollection, ByVal pageIndex As Integer, _
            ByVal pageSize As Integer) As Dictionary(Of Integer, String)


        Dim links As New Dictionary(Of Integer, String)

        'Using serv As New eUtils.eUtilsService


        For Each dbName As String In dbs


            Dim res As eUtils.eSearchResultType

            'Retrieve list of UIDs from database
            res = Me.service.run_eSearch_MS(dbName, searchString, String.Empty, _
                  String.Empty, String.Empty, My.Settings.Tool, My.Settings.EmailAddress, _
                  String.Empty, String.Empty, String.Empty, String.Empty, String.Empty, _
                  pageIndex.ToString, pageSize.ToString, String.Empty, String.Empty)


            'links.AddRange(Me.ParseUids(res), dbName)
            links = AddLinksToDictionary(links, ParseUids(res), dbName)

        Next

        'End Using

        Return links

    End Function



#End Region

#Region " IDisposable Support "


    Private disposedValue As Boolean = False        ' To detect redundant calls

    ' IDisposable
    Protected Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: free managed resources when explicitly called

                Me.service.Dispose()

            End If

            ' TODO: free shared unmanaged resources
        End If
        Me.disposedValue = True
    End Sub


    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

